home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / smtpcli.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  21.7 KB  |  939 lines

  1. /*
  2.  *    CLIENT routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <time.h>
  16. #include <setjmp.h>
  17. #include "amiga/stat.h"
  18. #include "global.h"
  19. #include "config.h"
  20. #ifdef    ANSIPROTO
  21. #include <stdarg.h>
  22. #endif
  23. #include "mbuf.h"
  24. #include "cmdparse.h"
  25. #include "proc.h"
  26. #include "socket.h"
  27. #include "timer.h"
  28. #include "netuser.h"
  29. #include "smtp.h"
  30. #include "dirutil.h"
  31. #include "commands.h"
  32. #include "session.h"
  33. #include "bm.h"
  34.  
  35. static struct timer Smtpcli_t;
  36. int32 Gateway;
  37.  
  38. #ifdef SMTPTRACE
  39. static unsigned short Smtptrace = 0;        /* used for trace level */
  40. static int dosmtptrace __ARGS((int argc,char *argv[],void *p));
  41. #endif
  42.  
  43. static unsigned  short Smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  44. static int Smtpsessions = 0;        /* number of client connections
  45.                     * currently open */
  46.  
  47. static char smtp_recv[] = "smtp recv: %s\n";
  48. static int Smtpbatch;
  49.  
  50. int    Smtpmode = 0;
  51.  
  52. static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  53.  
  54. static void del_job __ARGS((struct smtp_job *jp));
  55. static void del_session __ARGS((struct smtpcli *cb));
  56. static int dogateway __ARGS((int argc,char *argv[],void *p));
  57. static int dosmtpmaxcli __ARGS((int argc,char *argv[],void *p));
  58. static int dotimer __ARGS((int argc,char *argv[],void *p));
  59. static int dosmtpkill __ARGS((int argc,char *argv[],void *p));
  60. static int dosmtplist __ARGS((int argc,char *argv[],void *p));
  61. static int dobatch __ARGS((int argc,char *argv[],void *p));
  62. static void execjobs __ARGS((void));
  63. static int getresp __ARGS((struct smtpcli *ftp,int mincode));
  64. static void logerr __ARGS((struct smtpcli *cb,char *line));
  65. static struct smtpcli *lookup __ARGS((int32 destaddr));
  66. static struct smtpcli *newcb __ARGS((void));
  67. static int next_job __ARGS((struct smtpcli *cb));
  68. static void retmail __ARGS((struct smtpcli *cb));
  69. static void sendcmd __ARGS((struct smtpcli *cb,char *fmt,...));
  70. static int smtpsendfile __ARGS((struct smtpcli *cb));
  71. static int setsmtpmode __ARGS((int argc,char *argv[],void *p));
  72. static struct smtp_job *setupjob __ARGS((struct smtpcli *cb,char *id,char *from));
  73. static void smtp_send __ARGS((int unused,void *cb1,void *p));
  74. static int smtpkick __ARGS((int argc,char *argv[],void *p));
  75.  
  76. extern int dosmtpaccept __ARGS((int argc,char *argv[],void *p));
  77. extern int dosmtpreject __ARGS((int argc,char *argv[],void *p));
  78.  
  79. static struct cmds Smtpcmds[] = {
  80.     "accept",    dosmtpaccept,    0,    0,    NULLCHAR,
  81.     "batch",    dobatch,    0,    0,    NULLCHAR,
  82.     "gateway",    dogateway,    0,    0,    NULLCHAR,
  83.     "mode",        setsmtpmode,    0,    0,    NULLCHAR,
  84.     "kick",        smtpkick,    0,    0,    NULLCHAR,
  85.     "kill",        dosmtpkill,    0,    2,    "kill <jobnumber>",
  86.     "list",        dosmtplist,    0,    0,    NULLCHAR,
  87.     "maxclients",    dosmtpmaxcli,    0,    0,    NULLCHAR,
  88.     "reject",    dosmtpreject,    0,    0,    NULLCHAR,
  89.     "timer",    dotimer,    0,    0,    NULLCHAR,
  90. #ifdef SMTPTRACE
  91.     "trace",    dosmtptrace,    0,    0,    NULLCHAR,
  92. #endif
  93.     NULLCHAR,
  94. };
  95.  
  96. int dosmtp(argc,argv,p)
  97. int argc;
  98. char *argv[];
  99. void *p;
  100. {
  101.     if(argc == 1)
  102.         return dosmtplist(argc,argv,p);
  103.     return subcmd(Smtpcmds,argc,argv,p);
  104. }
  105.  
  106. static int dobatch(argc,argv,p)
  107. int argc;
  108. char *argv[];
  109. void *p;
  110. {
  111.     return setbool(&Smtpbatch,"SMTP batching",argc,argv);
  112. }
  113.  
  114. static int dosmtpmaxcli(argc,argv,p)
  115. int argc;
  116. char *argv[];
  117. void *p;
  118. {
  119.     return setshort(&Smtpmaxcli,"Max clients",argc,argv);
  120. }
  121.  
  122. static int setsmtpmode(argc,argv,p)
  123. int argc;
  124. char *argv[];
  125. void *p;
  126. {
  127.     if (argc < 2) {
  128.         tprintf("smtp mode: %s\n",
  129.             (Smtpmode & QUEUE) ? "queue" : "route");
  130.     } else {
  131.         switch(*argv[1]) {
  132.         case 'q':
  133.             Smtpmode |= QUEUE;
  134.             break;
  135.         case 'r':
  136.             Smtpmode &= ~QUEUE;
  137.             break;
  138.         default:
  139.             tprintf("Usage: smtp mode [queue | route]\n");
  140.             break;
  141.         }
  142.     }
  143.     return 0;
  144. }
  145.  
  146. static int dogateway(argc,argv,p)
  147. int argc;
  148. char *argv[];
  149. void *p;
  150. {
  151.     int32 n;
  152.  
  153.     if(argc < 2){
  154.         tprintf("%s\n",inet_ntoa(Gateway));
  155.     } else if((n = resolve(argv[1])) == 0){
  156.         tprintf(Badhost,argv[1]);
  157.         return 1;
  158.     } else
  159.         Gateway = n;
  160.     return 0;
  161. }
  162.  
  163. #ifdef SMTPTRACE
  164. static int dosmtptrace(argc,argv,p)
  165. int argc;
  166. char *argv[];
  167. void *p;
  168. {
  169.     return setshort(&Smtptrace,"SMTP tracing",argc,argv);
  170. }
  171. #endif
  172.  
  173. /* list jobs wating to be sent in the mqueue */
  174. static int dosmtplist(argc,argv,p)
  175. int argc;
  176. char *argv[];
  177. void *p;
  178. {
  179.     char tstring[80];
  180.     char line[20];
  181.     char host[LINELEN];
  182.     char to[LINELEN];
  183.     char from[LINELEN];
  184.     char *cp;
  185.     char    status;
  186.     struct stat stbuf;
  187.     struct tm *tminfo, *localtime();
  188.     FILE *fp;
  189.  
  190.     Current->flowmode = 1; /* Enable the more mechanism */
  191.     tprintf("S     Job    Size Date  Time  Host                 From\n");
  192.     filedir(Mailqueue,0,line);
  193.     while(line[0] != '\0') {
  194.         sprintf(tstring,"%s/%s",Mailqdir,line);
  195.         if ((fp = fopen(tstring,READ_TEXT)) == NULLFILE) {
  196.             tprintf("Can't open %s: %s\n",tstring,sys_errlist[errno]);
  197.             continue;
  198.         }
  199.         if ((cp = strrchr(line,'.')) != NULLCHAR)
  200.             *cp = '\0';
  201.         sprintf(tstring,"%s/%s.lck",Mailqdir,line);
  202.         if (access(tstring,0))
  203.             status = ' ';
  204.         else
  205.             status = 'L';
  206.         sprintf(tstring,"%s/%s.txt",Mailqdir,line);
  207.         stat(tstring,&stbuf);
  208.         tminfo = localtime(&stbuf.st_ctime);
  209.         fgets(host,sizeof(host),fp);
  210.         rip(host);
  211.         fgets(from,sizeof(from),fp);
  212.         rip(from);
  213.         tprintf("%c %7s %7ld %02d/%02d %02d:%02d %-20s %s\n      ",
  214.             status, line, stbuf.st_size,
  215.             tminfo->tm_mon+1,
  216.             tminfo->tm_mday,
  217.             tminfo->tm_hour,
  218.             tminfo->tm_min,
  219.             host,from);
  220.         while (fgets(to,sizeof(to),fp) != NULLCHAR) {
  221.             rip(to);
  222.             tprintf("%s ",to);
  223.         }
  224.         tprintf("\n");
  225.         (void) fclose(fp);
  226.         pwait(NULL);
  227.         filedir(Mailqueue,1,line);
  228.     }
  229.     Current->flowmode = 0;
  230.     return 0;
  231. }
  232.  
  233. /* kill a job in the mqueue */
  234. static int dosmtpkill(argc,argv,p)
  235. int argc;
  236. char *argv[];
  237. void *p;
  238. {
  239.     char s[SLINELEN];
  240.     char *cp,c;
  241.     sprintf(s,"%s/%s.lck",Mailqdir,argv[1]);
  242.     cp = strrchr(s,'.');
  243.     if (!access(s,0)) {
  244.         c = keywait("Warning, the job is locked by SMTP. Remove (y/n)? ",0);
  245.         if (c != 'y')
  246.             return 0;
  247.         (void) unlink(s);
  248.     }
  249.     strcpy(cp,".wrk");
  250.     if (unlink(s))
  251.         tprintf("Job id %s not found\n",argv[1]);
  252.     strcpy(cp,".txt");
  253.     (void) unlink(s);
  254.     return 0;
  255. }
  256.  
  257. /* Set outbound spool scan interval */
  258. static int dotimer(argc,argv,p)
  259. int argc;
  260. char *argv[];
  261. void *p;
  262. {
  263.     if(argc < 2){
  264.         tprintf("%lu/%lu\n",
  265.         read_timer(&Smtpcli_t) * MSPTICK/1000,
  266.         dur_timer(&Smtpcli_t) * MSPTICK/1000);
  267.         return 0;
  268.     }
  269.     Smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
  270.     Smtpcli_t.arg = NULL;        /* dummy value */
  271.     Smtpcli_t.start = atol(argv[1])*(1000/MSPTICK);    /* set timer duration */
  272.     start_timer(&Smtpcli_t);        /* and fire it up */
  273.     return 0;
  274. }
  275.  
  276. static int smtpkick(argc,argv,p)
  277. int argc;
  278. char *argv[];
  279. void *p;
  280. {
  281.     smtptick(NULL);
  282.     return 0;
  283. }
  284.  
  285. /* This is the routine that gets called every so often to do outgoing
  286.  * mail processing. When called with a null argument, it runs the entire
  287.  * queue; if called with a specific non-zero IP address from the remote
  288.  * kick server, it only starts up sessions to that address.
  289.  */
  290. int smtptick(t)
  291. void *t;
  292. {
  293.     register struct smtpcli *cb;
  294.     struct smtp_job *jp;
  295.     struct list *ap;
  296.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  297.     char    from[LINELEN], to[LINELEN];
  298.     char *cp, *cp1;
  299.     int32 destaddr,target;
  300.     FILE *wfile;
  301.  
  302.     target = (int32)t;
  303.     if(availmem() < Memthresh){
  304.         /* Memory is tight, don't do anything */
  305.         /* Restart timer */
  306.         start_timer(&Smtpcli_t);
  307.         return 0;
  308.     }
  309.     for(filedir(Mailqueue,0,wfilename);wfilename[0] != '\0';
  310.         filedir(Mailqueue,1,wfilename)){
  311.  
  312.         /* save the prefix of the file name which it job id */
  313.         cp = wfilename;
  314.         cp1 = prefix;
  315.         while (*cp && *cp != '.')
  316.             *cp1++ = *cp++;
  317.         *cp1 = '\0';
  318.  
  319.         /* lock this file from the smtp daemon */
  320.         if (mlock(Mailqdir,prefix))
  321.             continue;
  322.  
  323.         sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
  324.         if ((wfile = fopen(tmpstring,READ_TEXT)) == NULLFILE) {
  325.             /* probably too many open files */
  326.             (void) rmlock(Mailqdir,prefix);
  327.             /* continue to next message. The failure
  328.             * may be temporary */
  329.             continue;
  330.         }
  331.  
  332.         (void) fgets(tmpstring,LINELEN,wfile);    /* read target host */
  333.         rip(tmpstring);
  334.         if ((destaddr = mailroute(tmpstring)) == 0) {
  335.             fclose(wfile);
  336.             printf("** smtp: Unknown address %s\n",tmpstring);
  337.             (void) rmlock(Mailqdir,prefix);
  338.             continue;
  339.         }
  340.         if(target != 0 && destaddr != target){
  341.             fclose(wfile);
  342.             (void) rmlock(Mailqdir,prefix);
  343.             continue;    /* Not the proper target of a kick */
  344.         }
  345. #ifdef SMTPTRACE
  346.     if (Smtptrace > 5)
  347.         printf("smtp daemon entered, target = %s : destaddr = %s\n",
  348.             inet_ntoa(target), inet_ntoa(destaddr));
  349. #endif
  350.         if ((cb = lookup(destaddr)) == NULLSMTPCLI) {
  351.             /* there are enough processes running already */
  352.             if (Smtpsessions >= Smtpmaxcli) {
  353. #ifdef SMTPTRACE
  354.                 if (Smtptrace) {
  355.                     printf("smtp daemon: too many processes\n");
  356.                 }
  357. #endif
  358.                 fclose(wfile);
  359.                 (void) rmlock(Mailqdir,prefix);
  360.                 break;
  361.             }
  362.             if ((cb = newcb()) == NULLSMTPCLI) {
  363.                 fclose(wfile);
  364.                 (void) rmlock(Mailqdir,prefix);
  365.                 break;
  366.             } 
  367.             cb->ipdest = destaddr;
  368.             cb->destname = strdup(tmpstring);
  369.         } else {
  370.             if(cb->lock){
  371.                 /* This system is already is sending mail lets not
  372.                 * interfere with its send queue.
  373.                 */
  374.                 fclose(wfile);
  375.                 (void) rmlock(Mailqdir,prefix);
  376.                 continue;
  377.             }
  378.         }
  379.  
  380.         (void) fgets(from,LINELEN,wfile);    /* read from */
  381.         rip(from);
  382.         if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  383.             fclose(wfile);
  384.             (void) rmlock(Mailqdir,prefix);
  385.             del_session(cb);
  386.             break;
  387.         }
  388.         while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  389.             rip(to);
  390.             if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  391.                 fclose(wfile);
  392.                 del_session(cb);
  393.             }
  394.         }
  395.         fclose(wfile);
  396. #ifdef SMTPTRACE
  397.         if (Smtptrace > 1) {
  398.             printf("queue job %s From: %s To:",prefix,from);
  399.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  400.                 printf(" %s",ap->val);
  401.             printf("\n");
  402.         }
  403. #endif
  404.     }
  405.  
  406.     /* start sending that mail */
  407.     execjobs();
  408.  
  409.     /* Restart timer */
  410.     start_timer(&Smtpcli_t);
  411.     return 0;
  412. }
  413.  
  414. /* This is the master state machine that handles a single SMTP transaction.
  415.  * It is called with a queue of jobs for a particular host.
  416.  * The logic is complicated by the "Smtpbatch" variable, which controls
  417.  * the batching of SMTP commands. If Smtpbatch is true, then many of the
  418.  * SMTP commands are sent in one swell foop before waiting for any of
  419.  * the responses. Unfortunately, this breaks many brain-damaged SMTP servers
  420.  * out there, so provisions have to be made to operate SMTP in lock-step mode.
  421.  */
  422. static void smtp_send(unused,cb1,p)
  423. int unused;
  424. void *cb1;
  425. void *p;
  426. {
  427.     register struct smtpcli *cb;
  428.     register struct list *tp;
  429.     struct sockaddr_in fsocket;
  430.     char *cp;
  431.     int rcode;
  432.     int rcpts;
  433.     int goodrcpt;
  434.     int i;
  435.     int init = 1;
  436.     int smtpbatch;
  437.  
  438.     cb = (struct smtpcli *)cb1;
  439.     cb->lock = 1;
  440.     fsocket.sin_family = AF_INET;
  441.     fsocket.sin_addr.s_addr = cb->ipdest;
  442.     fsocket.sin_port = IPPORT_SMTP;
  443.  
  444.     cb->s = socket(AF_INET,SOCK_STREAM,0);
  445.         setflush(cb->s,-1);    /* We'll explicitly flush before reading */
  446. #ifdef SMTPTRACE
  447.     if (Smtptrace) 
  448.         printf("SMTP client Trying...\n");
  449. #endif
  450.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == 0){
  451. #ifdef SMTPTRACE
  452.     if (Smtptrace) 
  453.         printf("Connected\n");
  454. #endif
  455.         ;
  456.     } else {
  457.         cp = sockerr(cb->s);
  458. #ifdef SMTPTRACE
  459.         if (Smtptrace) 
  460.             printf("Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  461. #endif
  462.         mainlog(cb->s,"SMTP %s Connect failed: %s",psocket(&fsocket),
  463.             cp != NULLCHAR ? cp : "");
  464.     }
  465.     smtpbatch = Smtpbatch;
  466.     if(!smtpbatch){
  467.         rcode = getresp(cb,200);
  468.         if(rcode == -1 || rcode >= 400)
  469.             goto quit;
  470.     }
  471.     /* Say HELO */
  472.     sendcmd(cb,"HELO %s\n",Hostname);
  473.     if(!smtpbatch){
  474.         rcode = getresp(cb,200);
  475.         if(rcode == -1 || rcode >= 400)
  476.             goto quit;
  477.     }
  478.     do {    /* For each message... */
  479.  
  480.         /* if this file open fails, skip it */
  481.         if ((cb->tfile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  482.             continue;
  483.  
  484.         /* Send MAIL and RCPT commands */
  485.         sendcmd(cb,"MAIL FROM:<%s>\n",cb->jobq->from);
  486.         if(!smtpbatch){
  487.             rcode = getresp(cb,200);
  488.             if(rcode == -1 || rcode >= 400)
  489.                 goto quit;
  490.         }
  491.         rcpts = 0;
  492.         goodrcpt = 0;
  493.         for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  494.             sendcmd(cb,"RCPT TO:<%s>\n",tp->val);
  495.             if(!smtpbatch){
  496.                 rcode = getresp(cb,200);
  497.                 if(rcode == -1)
  498.                     goto quit;
  499.                 if(rcode < 400)
  500.                     goodrcpt = 1; /* At least one good */
  501.             }
  502.             rcpts++;
  503.         }
  504.         /* Send DATA command */
  505.         sendcmd(cb,"DATA\n");
  506.         if(!smtpbatch){
  507.             rcode = getresp(cb,200);
  508.             if(rcode == -1 || rcode >= 400)
  509.                 goto quit;
  510.         }
  511.         if(smtpbatch){
  512.             /* Now wait for the responses to come back. The first time
  513.              * we do this, we wait first for the start banner and
  514.              * HELO response. In any case, we wait for the response to
  515.              * the MAIL command here.
  516.              */
  517.             for(i= init ? 3 : 1;i > 0;i--){
  518.                 rcode = getresp(cb,200);
  519.                 if(rcode == -1 || rcode >= 400)
  520.                     goto quit;
  521.             }
  522.             init = 0;
  523.  
  524.             /* Now process the responses to the RCPT commands */
  525.             for(i=rcpts;i!=0;i--){
  526.                 rcode = getresp(cb,200);
  527.                 if(rcode == -1)
  528.                     goto quit;
  529.                 if(rcode < 400)
  530.                     goodrcpt = 1; /* At least one good */
  531.             }
  532.             /* And finally get the response to the DATA command.
  533.              * Some servers will return failure here if no recipients
  534.              * are valid, some won't.
  535.              */
  536.             rcode = getresp(cb,200);
  537.             if(rcode == -1 || rcode >= 400)
  538.                 goto quit;
  539.  
  540.             /* check for no good rcpt on the list */
  541.             if (goodrcpt == 0){
  542.                 sendcmd(cb,".\n");  /* Get out of data mode */
  543.                 goto quit;
  544.             }
  545.         }
  546.         /* Send the file. This also closes it */
  547.         smtpsendfile(cb);
  548.  
  549.         /* Wait for the OK response */
  550.         rcode = getresp(cb,200);
  551.         if(rcode == -1)
  552.             goto quit;
  553.         if((rcode >= 200 && rcode < 300) || rcode >= 500){
  554.             /* if a good transfer or permanent failure remove job */
  555.  
  556.             if (cb->errlog != NULLLIST)
  557.                 retmail(cb);
  558.             /* Unlink the textfile */
  559.             (void) unlink(cb->tname);
  560.             (void) unlink(cb->wname);    /* unlink workfile */
  561.             mainlog(cb->s,"SMTP sent job %s To: %s From: %s",
  562.              cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  563.         }
  564.     } while(next_job(cb));
  565. quit:
  566.     sendcmd(cb,"QUIT\n");
  567.     if (cb->errlog != NULLLIST){
  568.         retmail(cb);
  569.         (void) unlink(cb->wname);    /* unlink workfile */
  570.         (void) unlink(cb->tname);    /* unlink text */
  571.     }
  572.     (void) close_s(cb->s);
  573.     if(cb->tfile != NULLFILE)
  574.         fclose(cb->tfile);
  575.     cb->lock = 0;
  576.     del_session(cb);
  577. }
  578.  
  579. /* create mail lockfile */
  580. int mlock(dir,id)
  581. char *dir,*id;
  582. {
  583.     char lockname[LINELEN];
  584.     int fd;
  585.  
  586.     /* Try to create the lock file in an atomic operation */
  587.     sprintf(lockname,"%s/%s.lck",dir,id);
  588.     if(access(lockname, 0) == 0)
  589.         return -1;
  590.     if((fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT,0600)) == -1)
  591.         return -1;
  592.     close(fd);
  593.     return 0;
  594. }
  595.  
  596. /* remove mail lockfile */
  597. int rmlock(dir,id)
  598. char *dir,*id;
  599. {
  600.     char lockname[LINELEN];
  601.     sprintf(lockname,"%s/%s.lck",dir,id);
  602.     return(unlink(lockname));
  603. }
  604.  
  605. /* free the message struct and data */
  606. static void del_session(cb)
  607. register struct smtpcli *cb;
  608. {
  609.     register struct smtp_job *jp,*tp;
  610.     register int i;
  611.  
  612.     if (cb == NULLSMTPCLI)
  613.         return;
  614.     for(i=0; i<MAXSESSIONS; i++) 
  615.         if(cli_session[i] == cb) {
  616.             cli_session[i] = NULLSMTPCLI;
  617.             break;
  618.         }
  619.  
  620.     free(cb->wname);
  621.     free(cb->tname);
  622.     free(cb->destname);
  623.     for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  624.             tp = jp->next;
  625.             del_job(jp);
  626.     }
  627.     del_list(cb->errlog);
  628.     free((char *)cb);
  629.     Smtpsessions--;    /* number of connections active */
  630. }
  631.  
  632. static void del_job(jp)
  633. register struct smtp_job *jp;
  634. {
  635.     if ( *jp->jobname != '\0')
  636.         (void) rmlock(Mailqdir,jp->jobname);
  637.     free(jp->from);
  638.     del_list(jp->to);
  639.     free((char *)jp);
  640. }
  641.  
  642. /* delete a list of list structs */
  643. void del_list(lp)
  644. struct list *lp;
  645. {
  646.     register struct list *tp, *tp1;
  647.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  648.         tp1 = tp->next;
  649.         free(tp->val);
  650.         free((char *)tp);
  651.     }
  652. }
  653.  
  654. /* return message to sender */
  655. static void retmail(cb)
  656. struct smtpcli *cb;
  657. {
  658.     register struct list *lp;
  659.     register FILE *tfile;
  660.     register int c;
  661.     FILE *infile;
  662.     char *to;
  663.     time_t t;
  664.  
  665. #ifdef SMTPTRACE
  666.     if (Smtptrace > 5) {
  667.         printf("smtp job %s returned to sender\n",cb->wname);
  668.     }
  669. #endif
  670.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  671.     to = cb->jobq->from;
  672.     if (*to == '\0')
  673.         return;
  674.     if ((infile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  675.         return;
  676.     if ((tfile = tmpfile()) == NULLFILE) {
  677.         fclose(infile);
  678.         return;
  679.     }
  680.     time(&t);
  681.     fprintf(tfile,"%s%s",Hdrs[DATE],ptime(&t));
  682.     fprintf(tfile,"%s<%ld@%s>\n",Hdrs[MSGID],get_msgid(),Hostname);
  683.     fprintf(tfile,"%sMAILER-DAEMON@%s (Mail Delivery Subsystem)\n",
  684.         Hdrs[FROM],Hostname);
  685.     fprintf(tfile,"%s%s\n",Hdrs[TO],to);
  686.     fprintf(tfile,"%sFailed mail\n\n",Hdrs[SUBJECT]);
  687.     fprintf(tfile,"  ===== transcript follows =====\n\n");
  688.  
  689.     for (lp = cb->errlog; lp != NULLLIST; lp = lp->next)
  690.         fprintf(tfile,"%s\n",lp->val);
  691.  
  692.     fprintf(tfile,"\nMail Postmaster@%s for assistance.\n\n",Hostname);
  693.     fprintf(tfile,"\n  ===== Unsent message follows ====\n");
  694.  
  695.     while((c = getc(infile)) != EOF)
  696.         if (putc(c,tfile) == EOF)
  697.             break;
  698.     fclose(infile);
  699.     fseek(tfile,0L,0);
  700.     (void) mailuser(tfile,"",to);
  701.     fclose(tfile);
  702. }
  703.  
  704. /* look to see if a smtp control block exists for this ipdest */
  705. static struct smtpcli *lookup(destaddr)
  706. int32 destaddr;
  707. {
  708.     register int i;
  709.  
  710.     for(i=0; i<MAXSESSIONS; i++) {
  711.         if (cli_session[i] == NULLSMTPCLI)
  712.             continue;
  713.         if(cli_session[i]->ipdest == destaddr)
  714.             return cli_session[i];
  715.     }
  716.     return NULLSMTPCLI;
  717. }
  718.  
  719. /* create a new  smtp control block */
  720. static struct smtpcli *newcb()
  721. {
  722.     register int i;
  723.     register struct smtpcli *cb;
  724.  
  725.     for(i=0; i<MAXSESSIONS; i++) {
  726.         if(cli_session[i] == NULLSMTPCLI) {
  727.             cb = (struct smtpcli *)callocw(1,sizeof(struct smtpcli));
  728.             cb->wname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
  729.             cb->tname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
  730.             cli_session[i] = cb;
  731.             Smtpsessions++;    /* number of connections active */
  732.             return(cb);
  733.         }
  734.     }
  735.     return NULLSMTPCLI;
  736. }
  737.  
  738. static void execjobs()
  739. {
  740.     register struct smtpcli *cb;
  741.     register int i;
  742.  
  743.     for(i=0; i<MAXSESSIONS; i++) {
  744.         cb = cli_session[i];
  745.         if (cb == NULLSMTPCLI) 
  746.             continue;
  747.         if(cb->lock)
  748.             continue;
  749.  
  750.         sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
  751.         sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
  752.  
  753.         newproc("smtp_send", 1024, smtp_send, 0, cb,NULL);
  754.  
  755. #ifdef SMTPTRACE
  756.         if (Smtptrace) 
  757.             printf("Trying Connection to %s\n",inet_ntoa(cb->ipdest));
  758. #endif
  759.  
  760.     }
  761. }
  762.  
  763. /* add this job to control block queue */
  764. static struct smtp_job *setupjob(cb,id,from)
  765. struct smtpcli *cb;
  766. char *id,*from;
  767. {
  768.     register struct smtp_job *p1,*p2;
  769.  
  770.     p1 = (struct smtp_job *)callocw(1,sizeof(struct smtp_job));
  771.     p1->from = strdup(from);
  772.     strcpy(p1->jobname,id);
  773.     /* now add to end of jobq */
  774.     if ((p2 = cb->jobq) == NULLJOB)
  775.         cb->jobq = p1;
  776.     else {
  777.         while(p2->next != NULLJOB)
  778.             p2 = p2->next;
  779.         p2->next = p1;
  780.     }
  781.     return p1;
  782. }
  783.  
  784. /* called to advance to the next job */
  785. static int next_job(cb)
  786. register struct smtpcli *cb;
  787. {
  788.     register struct smtp_job *jp;
  789.  
  790.     jp = cb->jobq->next;
  791.     del_job(cb->jobq);
  792.     /* remove the error log of previous message */
  793.     del_list(cb->errlog);
  794.     cb->errlog = NULLLIST;
  795.     cb->jobq = jp;
  796.     if (jp == NULLJOB)
  797.         return 0;
  798.     sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
  799.     sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
  800. #ifdef SMTPTRACE
  801.     if (Smtptrace > 5) {
  802.         printf("sending job %s\n",jp->jobname);
  803.     }
  804. #endif
  805.         return 1;
  806.  
  807. }
  808.  
  809. /* Mail routing function. For now just use the hosts file */
  810. int32 mailroute(dest)
  811. char *dest;
  812. {
  813.     int32 destaddr;
  814.  
  815.     /* look up address or use the gateway */
  816.     if ((destaddr = resolve(dest)) == 0)
  817.         if (Gateway != 0) 
  818.             destaddr = Gateway; /* Use the gateway  */
  819.     return destaddr;
  820. }
  821.  
  822. /* save line in error list */
  823. static void logerr(cb,line)
  824. struct smtpcli *cb;
  825. char *line;
  826. {
  827.     register struct list *lp,*tp;
  828.     tp = (struct list *)callocw(1,sizeof(struct list));
  829.     tp->val = strdup(line);
  830.     /* find end of list */
  831.     if ((lp = cb->errlog) == NULLLIST)
  832.         cb->errlog = tp;
  833.     else {
  834.         while(lp->next != NULLLIST)
  835.             lp = lp->next;
  836.         lp->next = tp;
  837.     }
  838. }
  839.  
  840. static int smtpsendfile(cb)
  841. register struct smtpcli *cb;
  842. {
  843.     int error = 0;
  844.  
  845.     strcpy(cb->buf,"\n");
  846.     while(fgets(cb->buf,sizeof(cb->buf),cb->tfile) != NULLCHAR) {
  847.         /* Escape a single '.' character at the beginning of a line */
  848.         if(strcmp(cb->buf,".\n") == 0)
  849.             usputc(cb->s,'.');
  850.         usputs(cb->s,cb->buf);
  851.     }
  852.     fclose(cb->tfile);
  853.     cb->tfile = NULLFILE;
  854.     /* Send the end-of-message command */
  855.     if(cb->buf[strlen(cb->buf)-1] == '\n')
  856.         sendcmd(cb,".\n");
  857.     else
  858.         sendcmd(cb,"\n.\n");
  859.     return error;
  860. }
  861.  
  862. /* do a printf() on the socket with optional local tracing */
  863. #ifdef    ANSIPROTO
  864. static void sendcmd(struct smtpcli *cb,char *fmt, ...)
  865. {
  866.     va_list args;
  867.  
  868.     va_start(args,fmt);
  869. #ifdef    SMTPTRACE
  870.     if(Smtptrace){
  871.         printf("smtp sent: ");
  872.         vprintf(fmt,args);
  873.     }
  874. #endif
  875.     vsprintf(cb->buf,fmt,args);
  876.     usputs(cb->s,cb->buf);
  877.     va_end(args);
  878. }
  879. #else
  880. static void sendcmd(cb,fmt,arg1,arg2,arg3,arg4)
  881. struct smtpcli *cb;
  882. char *fmt;
  883. int arg1,arg2,arg3,arg4;
  884. {
  885. #ifdef    SMTPTRACE
  886.     if(Smtptrace){
  887.         printf("smtp sent: ");
  888.         printf(fmt,arg1,arg2,arg3,arg4);
  889.     }
  890. #endif
  891.     sprintf(cb->buf,fmt,arg1,arg2,arg3,arg4);
  892.     usputs(cb->s,cb->buf);
  893. }
  894. #endif
  895.  
  896. /* Wait for, read and display response from server. Return the result code. */
  897. static int getresp(cb,mincode)
  898. struct smtpcli *cb;
  899. int mincode;    /* Keep reading until at least this code comes back */
  900. {
  901.     int rval;
  902.     char line[LINELEN];
  903.  
  904.     usflush(cb->s);
  905.     for(;;){
  906.         /* Get line */
  907.         if(recvline(cb->s,line,LINELEN) == -1){
  908.             rval = -1;
  909.             break;
  910.         }
  911.         rip(line);        /* Remove cr/lf */
  912.         rval = atoi(line);
  913. #ifdef    SMTPTRACE
  914.         if(Smtptrace)
  915.             printf(smtp_recv,line);/* Display to user */
  916. #endif
  917.         if(rval >= 500) {    /* Save permanent error replies */
  918.             char tmp[LINELEN];
  919.             if(cb->errlog == NULLLIST) {
  920.                 sprintf(tmp,"While talking to %s:",
  921.                     cb->destname);
  922.                 logerr(cb,tmp);
  923.             }
  924.             if(cb->buf[0] != '\0') { /* Save offending command */
  925.                 rip(cb->buf);
  926.                 sprintf(tmp,">>> %s",cb->buf);
  927.                 logerr(cb,tmp);
  928.                 cb->buf[0] = '\0';
  929.             }
  930.             sprintf(tmp,"<<< %s",line);
  931.             logerr(cb,tmp);        /* save the error reply */
  932.         }
  933.         /* Messages with dashes are continued */
  934.         if(line[3] != '-' && rval >= mincode)
  935.             break;
  936.     }
  937.     return rval;
  938. }
  939.